package com.sjh.lib_app.statusMananger

import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout

/**
 * 多状态布局管理
 * 禁止在作为ViewPage的内容页时，使用最外层布局，可能会出现问题。
 * @author Extends
 * @date 2020/1/14/014
 */
class StatusManager private constructor(private val builder: Builder) {

    companion object {
        /**
         * 内容状态
         */
        const val STATUS_CONTEXT = "STATUSMANANGER_STATUS_CONTEXT"

        /**
         * 错误状态
         */
        const val STATUS_ERROR = "STATUSMANANGER_STATUS_ERROR"

        /**
         * 加载中状态
         */
        const val STATUS_LOADING = "STATUSMANANGER_STATUS_LOADING"

        /**
         * 空布局状态
         */
        const val STATUS_EMPTY = "STATUSMANANGER_STATUS_EMPTY"

        /**
         * 全局默认的状态布局，优先级最低，只有当没有手动设置的时候才会出现
         * 全局默认状态布局，不应该有内容布局，所以没有实现添加内容布局的方法
         */
        private val defaultStatusMap = hashMapOf<String, Class<out StatusView>>()

        /**
         * 全局添加默认的错误状态布局
         */
        fun addDefaultErrorStatus(default: Class<out StatusView>) {
            defaultStatusMap[STATUS_ERROR] = default
        }

        /**
         * 全局添加默认的空状态布局
         */
        fun addDefaultEmptyStatus(default: Class<out StatusView>) {
            defaultStatusMap[STATUS_EMPTY] = default
        }

        /**
         * 全局添加默认的加载中状态布局
         */
        fun addDefaultLoadingStatus(default: Class<out StatusView>) {
            defaultStatusMap[STATUS_LOADING] = default
        }

        /**
         * 全局添加默认的状态布局
         */
        fun addDefaultStatus(label: String, default: Class<out StatusView>) {
            defaultStatusMap[label] = default
        }
    }

    /**
     * 保存的父布局
     */
    private var parentView: ViewGroup? = null

    /**
     * 状态布局
     */
    private var statusLayout: FrameLayout? = null

    /**
     * 当前状态标签，默认是内容标签
     */
    private var currentLabel = STATUS_CONTEXT

    init {
        val contextView = builder.getStatus(STATUS_CONTEXT)
        this.parentView = contextView?.parent as? ViewGroup? ?: throw Exception("内容状态的父布局不能为空")


        statusLayout = FrameLayout(builder.context)
        //暂时不知道有什么副作用
        statusLayout!!.layoutParams = contextView.layoutParams
    }


    /**
     * 显示内容状态
     */
    fun showContextStatus() {
        showStatus(STATUS_CONTEXT)
    }

    /**
     * 显示加载中状态
     */
    fun showLoadingStatus() {
        showStatus(STATUS_LOADING)
    }

    /**
     * 显示错误状态
     * @param errorMsg 自定义的错误提示
     */
    fun showErrorStatus(errorMsg: String? = null) {
        showStatus(STATUS_ERROR, errorMsg)
    }

    /**
     * 显示空布局状态
     * @param emptyMsg 自定义的空数据提示
     */
    fun showEmptyStatus(emptyMsg: String? = null) {
        showStatus(STATUS_EMPTY, emptyMsg)
    }

    /**
     * 显示自定义状态
     */
    fun showStatus(status: String, info: String? = null) {
        try {
            if (status == currentLabel) return
            if (parentView == null) {
                Exception("父控件为null").printStackTrace()
                return
            }
            if (statusLayout == null) {
                Exception("状态布局为null").printStackTrace()
                return
            }

            //判断要显示的状态，如果要显示内容状态，需要脱壳
            if (status == STATUS_CONTEXT) {
                //把内容布局从它的父布局中移除
                //不把contextView添加进FrameLayout
                val contextView = builder.getStatus(STATUS_CONTEXT)
                (contextView?.parent as? ViewGroup?)?.removeView(contextView)
                //找到statusLayout的位置
                contextView?.visibility = View.VISIBLE
                val index = parentView!!.indexOfChild(statusLayout)
                //经过一次转换之后，丢失了之前的一些信息，这里赋值回来，保持原样
                contextView?.layoutParams = statusLayout!!.layoutParams
                parentView!!.removeViewAt(index)
                parentView!!.addView(contextView, index)
                parentView!!.invalidate()
            } else if (currentLabel == STATUS_CONTEXT) {
                //当前是内容布局的时候
                //找到内容布局在parentView中的位置并移除
                val contextView = builder.getStatus(STATUS_CONTEXT)
                val index = parentView!!.indexOfChild(contextView)
                parentView!!.removeViewAt(index)
                //判断statusLayout是否有父布局，如果有需要移除
                (statusLayout?.parent as? ViewGroup?)?.removeView(statusLayout)
                //清空statusLayout的子控件
                statusLayout?.removeAllViews()
                //添加指定的控件
                contextView?.visibility = View.INVISIBLE
                parentView!!.addView(statusLayout, index)
                statusLayout!!.addView(contextView, 0)
                statusLayout!!.addView(builder.getStatus(status), 1)
            } else {
                //当前是在statusLayout中进行操作
                //判断statusLayout的子控件是否是2个

                //先判断statusLayout是否在parentView中
                if (parentView!!.indexOfChild(statusLayout) < 0) {
                    val contextView = builder.getStatus(STATUS_CONTEXT)
                    val index = parentView!!.indexOfChild(contextView)
                    if (index < 0) {
                        Exception("父布局中既没有statusLayout也没有内容布局").printStackTrace()
                        return
                    }
                    parentView!!.removeViewAt(index)
                    parentView!!.addView(statusLayout, index)
                }
                val view = builder.getStatus(status)
                removeParent(view)
                if (statusLayout!!.childCount == 2 && statusLayout!!.getChildAt(0) == builder.getStatus(
                        STATUS_CONTEXT
                    )) {
                    statusLayout!!.removeViewAt(1)
                    statusLayout!!.addView(view, 1)
                } else {
                    //移除所有的子控件
                    statusLayout!!.removeAllViews()
                    val contextView = builder.getStatus(STATUS_CONTEXT)
                    removeParent(contextView)
                    contextView?.visibility = View.INVISIBLE
                    statusLayout!!.addView(contextView, 0)
                    statusLayout!!.addView(view, 1)
                }
            }
            when(status){
                STATUS_ERROR -> {
                    builder.getStatusView(status)?.setErrorMsg(info)
                }
                STATUS_EMPTY ->{
                    builder.getStatusView(status)?.setEmptyMsg(info)
                }
            }
            val oldLabel = currentLabel
            currentLabel = status
            builder.getChangeCall()?.change(currentLabel, oldLabel, this)
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    /**
     * 从view的父布局里面移除view
     */
    private fun removeParent(view: View?) {
        (view?.parent as? ViewGroup?)?.removeView(view)
    }

    /**
     * 设置点击事件
     * @param label 来源，使用方通过label来判断是哪里被点击了，需要做什么样的处理
     */
    fun setOnClickEvent(label: String) {
        this.builder.getClickCall()?.click(label)
    }

    @Deprecated("已废弃，两点无法实现：1. LayoutParams无法实现深拷贝。 2. 如果宽或者高是-2，则应该怎么显示，有三种可能性：-2，-1，具体值。")
    private fun getLayoutParams(contextView: ViewGroup) {
    }

    /**
     * 判断当前状态是否是指定的状态
     */
    fun isStatus(target: String) = currentLabel == target

    /**
     * 判断当前状态是否是内容状态
     */
    fun isContextStatus() = currentLabel == STATUS_CONTEXT

    /**
     * 判断当前状态是否是错误状态
     */
    fun isErrorStatus() = currentLabel == STATUS_ERROR

    /**
     * 判断当前状态是否是加载中状态
     */
    fun isLoadingStatus() = currentLabel == STATUS_LOADING

    /**
     * 判断当前状态是否是空布局状态
     */
    fun isEmptyStatus() = currentLabel == STATUS_EMPTY

    /**
     * 获取当前显示的View
     */
    fun getCurrentView(): View? {
        if (isContextStatus()) {
            return builder.getStatus(STATUS_CONTEXT)
        } else {
            return statusLayout
        }
    }

    class Builder(val context: Context) {
        /**
         * 所有的状态布局都存储在这
         */
        private val statusMap: HashMap<String, View?> = hashMapOf()

        /**
         * 继承于StatusView的状态先存储在这，随后会转移到statusMap中
         */
        private val mStatusMap: HashMap<String, StatusView?> = hashMapOf()

        /**
         * 点击事件监听
         */
        private var statusClickListener: StatusClickListener? = null

        /**
         * 状态改变监听
         */
        private var statusChangeListener: StatusChangeListener? = null

        /**
         * 指定显示的全局状态
         * 为了避免全局状态太多而添加的这个数组
         */
        private val onlySpecifiedMap: HashMap<String, String> = hashMapOf()

        /**
         * 设置点击监听
         */
        fun setOnClick(click: StatusClickListener): Builder {
            this.statusClickListener = click
            return this
        }

        /**
         * 设置状态改变监听
         */
        fun setOnStatusChangeListener(change: StatusChangeListener): Builder {
            this.statusChangeListener = change
            return this
        }

        fun getClickCall() = statusClickListener

        fun getChangeCall() = statusChangeListener

        /**
         * 设置内容状态
         */
        fun setContentStatus(contextView: View) = setStatus(STATUS_CONTEXT, contextView)

        /**
         * 设置错误状态
         */
        fun setErrorStatus(errorView: View) = setStatus(STATUS_ERROR, errorView)

        /**
         * 设置加载状态
         */
        fun setLoadingStatus(loadingView: View) = setStatus(STATUS_LOADING, loadingView)

        /**
         * 设置空状态
         */
        fun setEmptyStatus(emptyView: View) = setStatus(STATUS_EMPTY, emptyView)

        /**
         * 设置自定义布局
         */
        fun setStatus(status: String, view: View): Builder {
            statusMap[status] = view
            return this
        }

        /**
         * 设置错误状态
         */
        fun setErrorStatus(errorView: StatusView) = setStatus(STATUS_ERROR, errorView)

        /**
         * 设置加载状态
         */
        fun setLoadingStatus(loadingView: StatusView) = setStatus(STATUS_LOADING, loadingView)

        /**
         * 设置空状态
         */
        fun setEmptyStatus(emptyView: StatusView) = setStatus(STATUS_EMPTY, emptyView)

        /**
         * 设置自定义布局
         */
        fun setStatus(status: String, statusView: StatusView): Builder {
            mStatusMap[status] = statusView
            return this
        }

        /**
         * 获取状态布局的抽象类
         */
        fun getStatusView(status: String): StatusView? = mStatusMap[status]

        /**
         * 获取自定义布局
         */
        fun getStatus(status: String) = statusMap[status]

        /**
         * 设置只显示指定标签的默认全局错误状态
         * 主要是为了避免全局状态设置的太多
         */
        fun onlyErrorStatus() = onlySpecifiedStatus(STATUS_ERROR)

        /**
         * 设置只显示指定标签的默认全局错误状态
         * 主要是为了避免全局状态设置的太多
         */
        fun onlyLoadingStatus() = onlySpecifiedStatus(STATUS_LOADING)

        /**
         * 设置只显示指定标签的默认全局错误状态
         * 主要是为了避免全局状态设置的太多
         */
        fun onlyEmptyStatus() = onlySpecifiedStatus(STATUS_EMPTY)

        /**
         * 设置只显示指定标签的默认全局状态
         * 主要是为了避免全局状态设置的太多
         */
        fun onlySpecifiedStatus(status: String): Builder {
            onlySpecifiedMap[status] = status
            return this
        }

        /**
         * 构建
         */
        fun builder(): StatusManager {
            if (statusMap[STATUS_CONTEXT] == null && mStatusMap[STATUS_CONTEXT] == null) {
                throw Exception("内容布局必须创建")
            }
            val sm = StatusManager(this)
            mStatusMap.forEach {
                statusMap[it.key] = it.value?.createView(context, sm)
            }
            //判断默认布局
            defaultStatusMap.forEach {
                //如果statusMap没有实现默认布局里面的东西，则需要添加进去
                //判断onlySpecifiedMap中是否要求显示
                if (!statusMap.containsKey(it.key) && (onlySpecifiedMap.count() == 0 || (onlySpecifiedMap.count() != 0 && onlySpecifiedMap.containsKey(
                        it.key
                    )))) {
                    statusMap[it.key] = it.value.newInstance().createView(context, sm)
                }
            }
            return sm
        }
    }
}